﻿using Ionic.Zip;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace ARchGL.Platform.IO
{
    class ZipHelper
    {
        #region old
        /// <summary>
        /// 压缩ZIP文件
        /// 支持多文件和多目录，或是多文件和多目录一起压缩
        /// </summary>
        /// <param name="list">待压缩的文件或目录集合</param>
        /// <param name="strZipName">压缩后的文件名</param>
        /// <param name="IsDirStruct">是否按目录结构压缩</param>
        /// <returns>成功：true/失败：false</returns>
        public static bool CompressMulti(List<string> list, string strZipName, bool IsDirStruct)
        {
            try
            {
                using (ZipFile zip = new ZipFile(Encoding.Default))//设置编码，解决压缩文件时中文乱码
                {
                    foreach (string path in list)
                    {
                        string fileName = Path.GetFileName(path);//取目录名称
                        //如果是目录
                        if (Directory.Exists(path))
                        {
                            if (IsDirStruct)//按目录结构压缩
                            {
                                zip.AddDirectory(path, fileName);
                            }
                            else//目录下的文件都压缩到Zip的根目录
                            {
                                zip.AddDirectory(path);
                            }
                        }
                        if (File.Exists(path))//如果是文件
                        {
                            zip.AddFile(path);
                        }
                    }
                    zip.Save(strZipName);//压缩
                    return true;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 解压ZIP文件
        /// </summary>
        /// <param name="zipFileName">待解压的ZIP文件</param>
        /// <param name="extractPath">解压的目录</param>
        /// <param name="overWrite">是否覆盖</param>
        /// <returns>成功：true/失败：false</returns>
        public static bool Decompression(string zipFileName, string extractPath, bool overWrite)
        {
            try
            {
                using (var zip = new ZipFile(zipFileName, Encoding.GetEncoding("GBK"))) //处理中文解压缩乱码问题，注意：必须先注册编码页才能使用  Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);   //注册编码页
                {
                    zip.ExtractAll(extractPath, overWrite ? ExtractExistingFileAction.OverwriteSilently : ExtractExistingFileAction.DoNotOverwrite);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 得到指定的输入流的ZIP压缩流对象【原有流对象不会改变】
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <returns></returns>
        public static Stream ZipCompress(Stream sourceStream, string entryName = "zip")
        {
            MemoryStream compressedStream = new MemoryStream();
            if (sourceStream != null)
            {
                long sourceOldPosition = 0;
                try
                {
                    sourceOldPosition = sourceStream.Position;
                    sourceStream.Position = 0;
                    using (ZipFile zip = new ZipFile())
                    {
                        zip.AddEntry(entryName, sourceStream);
                        zip.Save(compressedStream);
                        compressedStream.Position = 0;
                    }
                }
                catch
                {
                }
                finally
                {
                    try
                    {
                        sourceStream.Position = sourceOldPosition;
                    }
                    catch
                    {
                    }
                }
            }
            return compressedStream;
        }

        /// <summary>
        /// 得到指定的字节数组的ZIP解压流对象
        /// 当前方法仅适用于只有一个压缩文件的压缩包，即方法内只取压缩包中的第一个压缩文件
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <returns></returns>
        public static Stream ZipDecompress(byte[] data)
        {
            Stream decompressedStream = new MemoryStream();
            if (data != null)
            {
                try
                {
                    MemoryStream dataStream = new MemoryStream(data);
                    using (ZipFile zip = ZipFile.Read(dataStream))
                    {
                        if (zip.Entries.Count > 0)
                        {
                            zip.Entries.First().Extract(decompressedStream);
                            // Extract方法中会操作ms，后续使用时必须先将Stream位置归零，否则会导致后续读取不到任何数据
                            // 返回该Stream对象之前进行一次位置归零动作
                            decompressedStream.Position = 0;
                        }
                    }
                }
                catch
                {
                }
            }
            return decompressedStream;
        }

        #endregion

        #region new

        /// <summary>
        /// 判断用户计算机是否安装了winrar压缩工具
        /// 如果已经安装winrar可通过如下代码返回winrar的安装位置，未安装则返回空字符串，最后并关闭注册表
        /// </summary>
        /// <returns></returns>
        public static string ExistsWinRar()
        {
            string result = string.Empty;

            string key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe";
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(key);
            if (registryKey != null)
            {
                result = registryKey.GetValue("").ToString();
                registryKey.Close();
            }

            return result;
        }


        /// <summary>

        /// 解压RAR和ZIP文件(需存在Winrar.exe(只要自己电脑上可以解压或压缩文件就存在Winrar.exe))

        /// </summary>

        /// <param name="UnPath">解压后文件保存目录</param>

        /// <param name="rarPathName">待解压文件存放绝对路径（包括文件名称）</param>

        /// <param name="IsCover">所解压的文件是否会覆盖已存在的文件(如果不覆盖,所解压出的文件和已存在的相同名称文件不会共同存在,只保留原已存在文件)</param>

        /// <param name="PassWord">解压密码(如果不需要密码则为空)</param>

        /// <returns>true(解压成功);false(解压失败)</returns>

        public static bool UnRarOrZip(string UnPath, string rarPathName, string winRar, bool IsCover, string PassWord)

        {

            if (!Directory.Exists(UnPath))

                Directory.CreateDirectory(UnPath);

            Process Process1 = new Process();

            Process1.StartInfo.FileName = winRar; //"Winrar.exe";

            Process1.StartInfo.CreateNoWindow = true;

            string cmd = "";

            if (!string.IsNullOrEmpty(PassWord) && IsCover)

                //解压加密文件且覆盖已存在文件( -p密码 )

                cmd = string.Format(" x -p{0} -o+ {1} {2} -y", PassWord, rarPathName, UnPath);

            else if (!string.IsNullOrEmpty(PassWord) && !IsCover)

                //解压加密文件且不覆盖已存在文件( -p密码 )

                cmd = string.Format(" x -p{0} -o- {1} {2} -y", PassWord, rarPathName, UnPath);

            else if (IsCover)

                //覆盖命令( x -o+ 代表覆盖已存在的文件)

                cmd = string.Format(" x -o+ {0} {1} -y", rarPathName, UnPath);

            else

                //不覆盖命令( x -o- 代表不覆盖已存在的文件)

                cmd = string.Format(" x -o- {0} {1} -y", rarPathName, UnPath);

            //命令

            Process1.StartInfo.Arguments = cmd;

            Process1.Start();

            Process1.WaitForExit();//无限期等待进程 winrar.exe 退出

            //Process1.ExitCode==0指正常执行，Process1.ExitCode==1则指不正常执行

            if (Process1.ExitCode == 0)

            {

                Process1.Close();

                return true;

            }

            else

            {

                Process1.Close();

                return false;

            }



        }



        /// <summary>

        /// 压缩文件成RAR或ZIP文件(需存在Winrar.exe(只要自己电脑上可以解压或压缩文件就存在Winrar.exe))

        /// </summary>

        /// <param name="filesPath">将要压缩的文件夹或文件的绝对路径</param>

        /// <param name="rarPathName">压缩后的压缩文件保存绝对路径（包括文件名称）</param>

        /// <param name="IsCover">所压缩文件是否会覆盖已有的压缩文件(如果不覆盖,所压缩文件和已存在的相同名称的压缩文件不会共同存在,只保留原已存在压缩文件)</param>

        /// <param name="PassWord">压缩密码(如果不需要密码则为空)</param>

        /// <returns>true(压缩成功);false(压缩失败)</returns>

        public static bool CondenseRarOrZip(string filesPath, string rarPathName, bool IsCover, string PassWord)

        {

            string rarPath = Path.GetDirectoryName(rarPathName);

            if (!Directory.Exists(rarPath))

                Directory.CreateDirectory(rarPath);

            Process Process1 = new Process();

            Process1.StartInfo.FileName = "Winrar.exe";

            Process1.StartInfo.CreateNoWindow = true;

            string cmd = "";

            if (!string.IsNullOrEmpty(PassWord) && IsCover)

                //压缩加密文件且覆盖已存在压缩文件( -p密码 -o+覆盖 )

                cmd = string.Format(" a -ep1 -p{0} -o+ {1} {2} -r", PassWord, rarPathName, filesPath);

            else if (!string.IsNullOrEmpty(PassWord) && !IsCover)

                //压缩加密文件且不覆盖已存在压缩文件( -p密码 -o-不覆盖 )

                cmd = string.Format(" a -ep1 -p{0} -o- {1} {2} -r", PassWord, rarPathName, filesPath);

            else if (string.IsNullOrEmpty(PassWord) && IsCover)

                //压缩且覆盖已存在压缩文件( -o+覆盖 )

                cmd = string.Format(" a -ep1 -o+ {0} {1} -r", rarPathName, filesPath);

            else

                //压缩且不覆盖已存在压缩文件( -o-不覆盖 )

                cmd = string.Format(" a -ep1 -o- {0} {1} -r", rarPathName, filesPath);

            //命令

            Process1.StartInfo.Arguments = cmd;

            Process1.Start();

            Process1.WaitForExit();//无限期等待进程 winrar.exe 退出

            //Process1.ExitCode==0指正常执行，Process1.ExitCode==1则指不正常执行

            if (Process1.ExitCode == 0)

            {

                Process1.Close();

                return true;

            }

            else

            {

                Process1.Close();

                return false;

            }
        }
        #endregion
    }
}
